package edu.towson.cosc.cosc455.jirani2.compiler;

import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

/** SyntaxAnalyzer is used imiate a recursive decent parser. Makes sure
 * All tags, and text allow the grammar rules
 * 
 */

public class MySyntaxAnalyzer implements SyntaxAnalyzer {

	/**
	 * Start non terminal symbol, to begin recursive decent parser
	 */
	@Override
	public void lolcode() {
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_BEGIN)){
			System.err.println("SYNTAX ERROR: " 
		+ MyCompiler.token + " when " + LexicalTokens.DOC_BEGIN + " was expected");
			System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.COMMENT_BEGIN)){
			comment();
			MyCompiler.Lexer.getNextToken();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_BEGIN)){
			define();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.HEAD_BEGIN)){
			head();
			MyCompiler.Lexer.getNextToken();
		}
		body();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.DOC_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.DOC_END + " was expected");
						System.exit(0);
		}
		//Makes sure no more tags after #KTHXBYE
		if(MyLexicalAnalyzer.currentPosition < MyCompiler.fileContents.toCharArray().length){
			System.err.println("SYNTAX ERROR: Cannot have token after " + LexicalTokens.DOC_END);
						System.exit(0);
		}
	}

	@Override
	public void comment() {
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.COMMENT_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.COMMENT_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void head() {
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.TITLE_BEGIN)){
			title();
		}
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.HEAD_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.HEAD_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void title() {
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.TITLE_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.TITLE_END + " was expected");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
	}

	@Override
	public void paragraph() {
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_BEGIN)){
			define();
		}
		innerParagraph();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.PARA_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.PARA_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void bold() {
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_BEGIN)){
			define();
		}
		innerText();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.BOLD_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.BOLD_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void italics() {
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_BEGIN)){
			define();
		}
		innerText();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITALICS_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.ITALICS_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void list() {
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITEM_BEGIN)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.ITEM_BEGIN + " was expected");
						System.exit(0);
		}
		item();//Maybe innerList
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.LIST_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.LIST_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void item() {
		MyCompiler.Lexer.getNextToken();
		innerList();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITEM_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.SOUND_END + " was expected");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITEM_BEGIN)){
			item();
		}
	}

	@Override
	public void audio() {
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.SOUND_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.SOUND_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void video() {
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.VIDEO_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.VIDEO_END + " was expected");
						System.exit(0);
		}
	}

	@Override
	public void define() {
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_MIDDLE)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.VAR_MIDDLE + " was expected");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.VAR_MIDDLE + " was expected");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_BEGIN)){
			define();
		}
	}

	@Override
	public void use() {
		MyCompiler.Lexer.getNextToken();
		if(!LexicalTokens.textDictionary.contains(MyCompiler.token)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " is not valid text");
						System.exit(0);
		}
		MyCompiler.Lexer.getNextToken();
		if(!MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_USE_END)){
			System.err.println("SYNTAX ERROR: " 
					+ MyCompiler.token + " when " + LexicalTokens.VAR_USE_END + " was expected");
						System.exit(0);
		}
	}
	
	/**
	 * Method to see if the current token has one of the possibilites
	 * for innerText, if so recursive call, otherwise, exits.
	 */
	public void innerText(){
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VAR_USE)){
			use();
			MyCompiler.Lexer.getNextToken();
			innerText();
		}
		//If text, just keep going, no need to process
		if(LexicalTokens.textDictionary.contains(MyCompiler.token)){
			MyCompiler.Lexer.getNextToken();
			innerText();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.NEWLINE)){
			MyCompiler.Lexer.getNextToken();
			innerText();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.SOUND_BEGIN)){
			audio();
			MyCompiler.Lexer.getNextToken();
			innerText();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.VIDEO_BEGIN)){
			audio();
			MyCompiler.Lexer.getNextToken();
			innerText();
		}
	}
	
	/**
	 * Method contains possibilies of inner-list, recursive call and then 
	 * exits if token does not fit
	 */
	public void innerList(){
		innerText();//See if inner-list, otherwise check other token possibilities
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BOLD_BEGIN)){
			bold();
			MyCompiler.Lexer.getNextToken();
			innerList();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITALICS_BEGIN)){
			italics();
			MyCompiler.Lexer.getNextToken();
			innerList();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.LIST_BEGIN)){
			list();
			MyCompiler.Lexer.getNextToken();
			innerList();
		}
	}
	
	/**
	 * This function holds the possibliities for tokens that can
	 * be contained within an inner-paragraph
	 */
	public void innerParagraph(){
		innerText();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BOLD_BEGIN)){
			bold();
			MyCompiler.Lexer.getNextToken();
			innerParagraph();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITALICS_BEGIN)){
			italics();
			MyCompiler.Lexer.getNextToken();
			innerParagraph();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.LIST_BEGIN)){
			list();
			MyCompiler.Lexer.getNextToken();
			innerParagraph();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.NEWLINE)){
			MyCompiler.Lexer.getNextToken();
			innerParagraph();
		}
	}
	
	/**
	 * Recursive void function, to repeat for possible comment, paragraph,
	 * inner-text etc. Only exits, when token does not fit.
	 */
	public void body(){
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.COMMENT_BEGIN)){
			comment();
			MyCompiler.Lexer.getNextToken();
			body();
		}
		innerText();
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.PARA_BEGIN)){
			paragraph();
			MyCompiler.Lexer.getNextToken();
			body();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.BOLD_BEGIN)){
			bold();
			MyCompiler.Lexer.getNextToken();
			body();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.ITALICS_BEGIN)){
			italics();
			MyCompiler.Lexer.getNextToken();
			body();
		}
		if(MyCompiler.token.equalsIgnoreCase(LexicalTokens.LIST_BEGIN)){
			list();
			MyCompiler.Lexer.getNextToken();
			body();
		}
	}

}
